package com.nx.arch.addon.lock.lock;

import java.net.SocketTimeoutException;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.nx.arch.addon.lock.client.RedisClient;
import com.nx.arch.addon.lock.exception.LockException;

/**
 * @类名称 RedisLock.java
 * @类描述 redis 锁
 * @作者  庄梦蝶殇 linhuaichuan@naixuejiaoyu.com
 * @创建时间 2020年4月7日 下午4:12:08
 * @版本 1.0.0
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     1.0.0 		庄梦蝶殇 	2020年4月7日             
 *     ----------------------------------------------
 * </pre>
 */
public class RedisLock extends BaseLock {
    private static Logger logger = LoggerFactory.getLogger("redis-lock");
    
    private final static String RESULT_OK = "OK";
    
    /**
     * redis客户端，基于jedis 实现
     */
    RedisClient client;
    
    /**
     * 续租线程
     */
    RenewalTask renewalTask;
    
    public RedisLock(RedisClient client, String key, boolean reentrant) {
        super(key, DEF_VAL, reentrant);
        this.client = client;
    }
    
    @Override
    protected boolean lock()
        throws LockException {
        try {
            // 抢锁
            if (RESULT_OK.equals(client.setNxPx(key, value, this.ttl))) {
                // 上报监控
                // NxMonitor.sum(30, 1);
                renewalTask = new RenewalTask();
                renewalTask.setDaemon(true);
                renewalTask.start();
                hold.set(true);
            } else {
                hold.set(false);
            }
        } catch (Exception e) {
            hold.set(false);
            Throwable cause = e.getCause();
            if (cause instanceof SocketTimeoutException) {
                return hold.get();
            }
            logger.error("Error encountered when attempting to acquire lock", e);
            throw e;
        } finally {
            if (reentrant && hold.get()) {
                holdLocks.get().add(key);
            }
        }
        return hold.get();
    }
    
    @Override
    public void release()
        throws LockException {
        if (hold.get()) {
            try {
                hold.set(false);
                client.delete(key, value);
                holdLocks.get().remove(key);
            } finally {
                if (renewalTask != null) {
                    renewalTask.close();
                }
            }
        }
    }
    
    @Override
    protected Object getClient() {
        return client;
    }
    /**
     * @类名称 RedisLock.java
     * @类描述 续租线程类
     * @作者  庄梦蝶殇 linhuaichuan@naixuejiaoyu.com
     * @创建时间 2020年4月7日 下午4:14:35
     * @版本 1.0.0
     *
     * @修改记录
     * <pre>
     *     版本                       修改人 		修改日期 		 修改内容描述
     *     ----------------------------------------------
     *     1.0.0 		庄梦蝶殇 	2020年4月7日             
     *     ----------------------------------------------
     * </pre>
     */
    class RenewalTask extends Thread {
        /**
         * 运行标识
         */
        public volatile boolean isRunning = true;
        
        @Override
        public void run() {
            while (isRunning) {
                try {
                    // 1、续租，刷新值
                    client.expire(key, ttl <= 0 ? 10 : ttl);
                    // 2、三分之一过期时间续租
                    TimeUnit.SECONDS.sleep((ttl <= 0 ? 10 : ttl) / 3);
                } catch (InterruptedException e) {
                    isRunning = false;
                }
            }
        }
        
        public void close() {
            isRunning = false;
        }
    }
}
